package service

import (
	"github.com/pkg/errors"
	"golang.org/x/exp/slices"
	"gorm.io/gorm"
	"zsc-boot/app/system_layer/model"
	"zsc-boot/app/system_layer/model/request"
	"zsc-boot/core/orm"
)

var ServiceRoleService = new(serviceRoleService)

type serviceRoleService struct {
}

// CreateRole 创建角色
func (s *serviceRoleService) CreateRole(role model.ServiceRole) (err error) {
	if !errors.Is(orm.GetDb().Where("name = ?", role.Name).First(&model.ServiceRole{}).Error, gorm.ErrRecordNotFound) { // 判断用户名是否注册
		return errors.New("角色名称已存在!")
	}
	if !errors.Is(orm.GetDb().Where("code = ?", role.Code).First(&model.ServiceRole{}).Error, gorm.ErrRecordNotFound) { // 判断编码是否注册
		return errors.New("角色编码已存在!")
	}
	err = orm.GetDb().Create(&role).Error
	return
}

// DeleteServiceRole 删除角色
func (s *serviceRoleService) DeleteServiceRole(role model.ServiceRole) (err error) {
	var serviceRole model.ServiceRole
	err = orm.GetDb().Model(&model.ServiceRole{}).Where("id = ?", role.ID).First(&serviceRole).Error
	if err != nil {
		return
	}

	var serviceUser model.ServiceUser
	orm.GetDb().Model(&model.ServiceUser{}).Where("role_id = ?", role.ID).First(&serviceUser)
	if serviceUser.ID > 0 {
		err = errors.New("角色绑定用户，不能删除")
		return
	}

	return orm.GetDb().Transaction(func(tx *gorm.DB) error {
		err = tx.Where("id = ?", role.ID).Delete(&role).Error
		if err != nil {
			return err
		}

		return tx.Where("role_code = ?", role.Code).Delete(&model.ServiceRoleMenu{}).Error
	})
}

// UpdateServiceRole 更新角色
func (s *serviceRoleService) UpdateServiceRole(role model.ServiceRole) (err error) {
	var oldRole model.ServiceRole
	err = orm.GetDb().Where("id = ?", role.ID).First(&oldRole).Error
	if err != nil {
		return
	}

	if !errors.Is(orm.GetDb().Where("name = ? and id != ?", role.Name, role.ID).First(&model.ServiceRole{}).Error, gorm.ErrRecordNotFound) { // 判断岗位名称是否存在
		return errors.New("角色名称已存在!")
	}
	if !errors.Is(orm.GetDb().Where("code = ? and id != ?", role.Code, role.ID).First(&model.ServiceRole{}).Error, gorm.ErrRecordNotFound) { // 判断岗位名称是否存在
		return errors.New("角色编码已存在!")
	}

	return orm.GetDb().Transaction(func(tx *gorm.DB) error {
		// 更新角色信息
		err = tx.Omit("created_at").Save(&role).Error
		if err != nil {
			return err
		}

		// 更新关联表中的角色编码
		return tx.Model(&model.ServiceRoleMenu{}).Where("role_code = ?", oldRole.Code).UpdateColumns(map[string]interface{}{
			"role_code": role.Code,
		}).Error
	})
}

// GetServiceRole 获取角色详情
func (s *serviceRoleService) GetServiceRole(id uint) (err error, resp model.ServiceRole) {
	err = orm.GetDb().Where("id = ?", id).First(&resp).Error
	return
}

// GetServiceRoleList 获取角色列表
func (s *serviceRoleService) GetServiceRoleList(info request.ServiceRoleSearch) (err error, list interface{}, total int64) {
	limit := info.PageSize
	offset := info.PageSize * (info.Page - 1)
	var serviceRoles []model.ServiceRole
	db := orm.GetDb().Model(&model.ServiceRole{})
	if info.Name != "" {
		db.Where("name like ?", "%"+info.Name+"%")
	}
	if info.Status != "" {
		db.Where("status = ?", info.Status)
	}
	err = db.Count(&total).Error
	if err != nil {
		return
	}
	err = db.Limit(limit).Offset(offset).Order("sequence").Find(&serviceRoles).Error
	return err, serviceRoles, total
}

// QueryMenuByRole 根据角色获取菜单权限
func (s *serviceRoleService) QueryMenuByRole(queryMenuByRoleRequest request.QueryMenuByRoleRequest) (err error, menuTree []model.ServiceMenu) {
	var menuCodeList []string
	err = orm.GetDb().Model(&model.ServiceRoleMenu{}).Where("role_code = ?", queryMenuByRoleRequest.Code).
		Pluck("menu_code", &menuCodeList).Error
	if err != nil {
		return
	}

	var menuList []model.ServiceMenu
	err = orm.GetDb().Model(&model.ServiceMenu{}).Where("rule_path in ?", menuCodeList).
		Where("visible = 2 and status = ?", "启用").
		Order("sequence desc").Find(&menuList).Error
	if err != nil {
		return
	}

	// 构建层级菜单树
	menuTree = BuildMenuTree(menuList, 0)
	return
}

// BuildMenuTree 递归构建层级菜单树
func BuildMenuTree(menus []model.ServiceMenu, parentId uint) []model.ServiceMenu {
	var tree []model.ServiceMenu
	for _, menu := range menus {
		if menu.ParentId == parentId {
			// 递归调用为当前菜单找子菜单
			menu.Children = BuildMenuTree(menus, menu.ID)
			tree = append(tree, menu)
		}
	}
	return tree
}

// UpdateMenuByRole 根据角色更新菜单权限
func (s *serviceRoleService) UpdateMenuByRole(updateMenuByRoleRequest request.UpdateMenuByRoleRequest) (err error) {
	var oldMenuCodeList []string
	err = orm.GetDb().Model(&model.ServiceRoleMenu{}).
		Where("role_code = ?", updateMenuByRoleRequest.RoleCode).
		Pluck("menu_code", &oldMenuCodeList).Error
	if err != nil {
		return
	}

	// 需要新增的菜单
	var needCreateMenuList []model.ServiceRoleMenu
	for _, menuCode := range updateMenuByRoleRequest.MenuCodes {
		if !slices.Contains(oldMenuCodeList, menuCode) {
			needCreateMenuList = append(needCreateMenuList, model.ServiceRoleMenu{
				RoleCode: updateMenuByRoleRequest.RoleCode,
				MenuCode: menuCode,
			})
		}
	}

	return orm.GetDb().Transaction(func(tx *gorm.DB) error {
		// 删除关联
		err = tx.Model(&model.ServiceRoleMenu{}).
			Where("role_code = ?", updateMenuByRoleRequest.RoleCode).
			Where("menu_code not in ?", updateMenuByRoleRequest.MenuCodes).
			Delete(&model.ServiceRoleMenu{}).Error
		if err != nil {
			return err
		}

		// 建立关联
		if len(needCreateMenuList) > 0 {
			return tx.Model(&model.ServiceRoleMenu{}).Create(&needCreateMenuList).Error
		}
		return nil
	})
}
